package com.lf.interceptor;

import com.alibaba.fastjson.JSONArray;
import com.lf.constant.ConstantsValue;
import com.lf.entity.ResponseWrapper;
import com.lf.enums.ErrorCodeEnum;
import com.lf.jwt.CurrentManager;
import com.lf.jwt.CurrentShop;
import com.lf.jwt.RepeatedlyReadRequestWrapper;
import com.lf.jwt.SameUrlData;
import com.lf.jwt2admin.ManagerToken;
import com.lf.util.StringUtils;
import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.JSONObject;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.redis.core.StringRedisTemplate;
import org.springframework.stereotype.Component;
import org.springframework.web.method.HandlerMethod;
import org.springframework.web.servlet.handler.HandlerInterceptorAdapter;

import javax.servlet.ServletRequest;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.BufferedReader;
import java.io.IOException;
import java.lang.reflect.Method;
import java.nio.charset.StandardCharsets;
import java.util.HashMap;
import java.util.Iterator;
import java.util.Map;
import java.util.concurrent.TimeUnit;

/**
 * @program: pzsh
 * @description:
 * @author: gxl
 * @create: 2019-12-05
 **/
@Slf4j
@Component
public class TokenInterceptor extends HandlerInterceptorAdapter {


    @Autowired
    public StringRedisTemplate stringRedisTemplate;
    @Override
    public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {

        if (!(handler instanceof HandlerMethod)) {
            return true;
        }

        HandlerMethod handlerMethod = (HandlerMethod) handler;

        //前端用戶token
        CurrentManager currentManager = handlerMethod.getMethodAnnotation(CurrentManager.class);
        if (currentManager == null) {
            currentManager = handlerMethod.getBeanType().getAnnotation(CurrentManager.class);
        }
        //方法注解判断是否需要token值
        if (currentManager != null && currentManager.value()) {
            JSONObject json = getRequestJsonObject(request);
            String token = json.getString("token");
            if (StringUtils.isBlank(token)) {
                token = request.getHeader("token");
            }
            if (StringUtils.isBlank(token)) {
                response.setContentType("application/json;charset=utf-8");
                response.getWriter().write(JSON.toJSONString(ResponseWrapper.failed(ErrorCodeEnum.TK1009)));
                return false;
            }
        }

        //管理員token
        ManagerToken managerToken = handlerMethod.getMethodAnnotation(ManagerToken.class);
        if (managerToken == null) {
            managerToken = handlerMethod.getBeanType().getAnnotation(ManagerToken.class);
        }
        //方法注解判断是否需要token值
        if (managerToken != null && managerToken.value()) {
            JSONObject json = getRequestJsonObject(request);
            String token = json == null ? null : json.getString("token");
            if (StringUtils.isBlank(token)) {
                token = request.getHeader("token");
            }
            if (StringUtils.isBlank(token)) {
                response.setContentType("application/json;charset=utf-8");
                response.getWriter().write(JSON.toJSONString(ResponseWrapper.failed(ErrorCodeEnum.TK1009)));
                return false;
            }
        }


//        Method method = handlerMethod.getMethod();
        SameUrlData annotation = handlerMethod.getMethodAnnotation(SameUrlData.class);
        if (annotation != null) {
            if(repeatDataValidator(request)){
                //请求数据相同
                log.warn("please don't repeat submit,url:"+ request.getServletPath());
                JSONObject result = new JSONObject();
                result.put("code","500");
                result.put("message","请勿重复请求");
                response.setCharacterEncoding("UTF-8");
                response.setContentType("application/json; charset=utf-8");
                response.getWriter().write(result.toString());
                response.getWriter().close();
//                    拦截之后跳转页面
//                    String formRequest = request.getRequestURI();
//                    request.setAttribute("myurl", formRequest);
//                    request.getRequestDispatcher("/WebRoot/common/error/jsp/error_message.jsp").forward(request, response);
                return false;
            }else {//如果不是重复相同数据
                return true;
            }
        }

        //方法注解判断是否需要shopId值
//        CurrentShop currentShop = handlerMethod.getMethodAnnotation(CurrentShop.class);
//        if (currentShop == null) {
//            currentShop = handlerMethod.getBeanType().getAnnotation(CurrentShop.class);
//        }
//        if (currentShop != null) {
//            JSONObject json = getRequestJsonObject(request);
//
//            if (!json.containsKey("shopId") || json.get("shopId") == null) {
//                response.setContentType("application/json;charset=utf-8");
//                response.getWriter().write(JSON.toJSONString(ResponseWrapper.failed(ErrorCodeEnum.TK1010)));
//                return false;
//            }
//        }
        return super.preHandle(request, response, handler);
    }


    /**
     * 验证同一个url数据是否相同提交,相同返回true
     * @param httpServletRequest
     * @return
     */
    public boolean repeatDataValidator(HttpServletRequest httpServletRequest) throws Exception{

        //获取请求参数map
//        JSON jsonObject = this.getJSONObject(httpServletRequest);
        JSONObject jsonObject = this.getRequestJsonObject(httpServletRequest);
        Map<String, String> parameterMap = JSON.parseObject(jsonObject.toJSONString(), Map.class);
//        Map<String, String[]> parameterMap = httpServletRequest.getParameterMap();
        Iterator<Map.Entry<String, String>> it = parameterMap.entrySet().iterator();
        String token = "";
        Map<String, String> parameterMapNew = new HashMap<>();
        while(it.hasNext()){
            Map.Entry<String, String> entry = it.next();
            if(!entry.getKey().equals("timeStamp") && !entry.getKey().equals("sign")){
                //去除sign和timeStamp这两个参数，因为这两个参数一直在变化
                parameterMapNew.put(entry.getKey(), entry.getValue());
                if(entry.getKey().equals("token")) {
                    token = entry.getValue();
                }
            }
        }
        //小程序请求一般用参数用户ID即可识别，普通web或app如果用到token作为身份识别，解开注释
//        if (StringUtils.isBlank(token)){
        //如果没有token，直接放行
//            return false;
//        }
        //过滤过后的请求内容
        String params = JSONObject.toJSONString(parameterMapNew);

//        System.out.println("params==========="+params);

        String url = httpServletRequest.getRequestURI();
        Map<String,String> map = new HashMap<>();
        //key为接口，value为参数
        map.put(url, params);
        String nowUrlParams = map.toString();

//        StringRedisTemplate smsRedisTemplate = SpringKit.getBean(StringRedisTemplate.class);
        String redisKey = token + url;
        String preUrlParams = stringRedisTemplate.opsForValue().get(redisKey);
        if(preUrlParams == null){
            //如果上一个数据为null,表示还没有访问页面
            //存放并且设置有效期，5秒
            stringRedisTemplate.opsForValue().set(redisKey, nowUrlParams, 3, TimeUnit.SECONDS);
            return false;
        }else{//否则，已经访问过页面
            if(preUrlParams.equals(nowUrlParams)){
                //如果上次url+数据和本次url+数据相同，则表示重复添加数据
                return true;
            }else{//如果上次 url+数据 和本次url加数据不同，则不是重复提交
//                stringRedisTemplate.opsForValue().set(redisKey, nowUrlParams, 1, TimeUnit.SECONDS);
                return false;
            }
        }
    }


    private JSON getJSONObject(HttpServletRequest req) {
        String str = null, retStr = "";
        try {
            BufferedReader br = req.getReader();
            while ((str = br.readLine()) != null) {
                retStr += str;
            }
            if (StringUtils.isNotBlank(retStr)) {
                JSONObject jsonObject = JSONObject.parseObject(retStr);
                if (null == jsonObject) {
                    JSONArray.parseArray(retStr);
                }
                return jsonObject;
            }
        } catch (Exception e) {
            try {
                return JSONArray.parseArray(retStr);
            } catch (Exception ex) {
                return null;
            }
        }
        return null;
    }


    public static JSONObject getRequestJsonObject(HttpServletRequest request) throws IOException {
        try {
            BufferedReader br = request.getReader();
            String str = null, retStr = "";
            while ((str = br.readLine()) != null) {
                retStr += str;
            }
            if (StringUtils.isNotBlank(retStr)) {
                JSONObject jsonObject = JSONObject.parseObject(retStr);
                return jsonObject;
            }
        } catch (Exception e) {
        }
        return null;
    }

    /***
     * 获取 request 中 json 字符串的内容
     */
    public static String getRequestJsonString(HttpServletRequest request)
            throws IOException {
        String submitMehtod = request.getMethod();
        // GET
        if (submitMehtod.equals("GET")) {
            return new String(request.getQueryString().getBytes(StandardCharsets.ISO_8859_1), StandardCharsets.UTF_8).replaceAll("%22",
                    "\"");
            // POST
        } else {
            return getRequestPostStr(request);
        }
    }

    /**
     * 描述:获取 post 请求内容
     */
    public static String getRequestPostStr(HttpServletRequest request) throws IOException {
        byte buffer[] = getRequestPostBytes(request);
        String charEncoding = request.getCharacterEncoding();
        if (charEncoding == null) {
            charEncoding = ConstantsValue.ENCODING_FORMAT_UTF8;
        }
        return new String(buffer, charEncoding);
    }

    /**
     * 描述:获取 post 请求的 byte[] 数组
     */
    public static byte[] getRequestPostBytes(HttpServletRequest request)
            throws IOException {
        int contentLength = request.getContentLength();
        if (contentLength < 0) {
            return null;
        }
        byte buffer[] = new byte[contentLength];
        for (int i = 0; i < contentLength; ) {
            int readlen = request.getInputStream().read(buffer, i, contentLength - i);
            if (readlen == -1) {
                break;
            }
            i += readlen;
        }
        return buffer;
    }
}
